#!/usr/bin/env python
import sys

from PyQt5.QtCore import (pyqtProperty, pyqtSignal, pyqtSlot, Q_CLASSINFO,
        QCoreApplication, QDate, QObject, QTime, QTimer, QUrl)
from PyQt5.QtGui import QColor
from PyQt5.QtQml import (qmlAttachedPropertiesObject, qmlRegisterType,
        QQmlComponent, QQmlEngine, QQmlListProperty, QQmlProperty,
        QQmlPropertyValueSource,QQmlApplicationEngine)
from PyQt5.QtWidgets import QApplication

QML = b'''
import People 1.0
import QtQuick 2.0
import QtQuick 2.0
import QtQuick.Window 2.0
import Qt.labs.qmlmodels 1.0
import QtQuick.Controls 2.12
Window {
    visible: true
    width: 640
    height: 480
    id:window1
    title: qsTr("Hello World")
    Button{
        text:"start"
        onClicked:()=>{
            console.log(party1.guestCount())
            //party1.startParty();
            //song1.start();
        }
    }
    BirthdayParty {
        id:party1
        HappyBirthdaySong on announcement { 
            id:song1
            name: "Bob Jones" 
        }

        onPartyStarted: console.log("This party started rockin' at " + time);

        host: Boy {
            name: "Bob Jones"
            shoe { size: 12; color: "white"; brand: "Nike"; price: 90.0 }
        }

        Boy {
            name: "Leo Hodges"
            BirthdayParty.rsvp: "2009-07-06"
            shoe { size: 10; color: "black"; brand: "Reebok"; price: 59.95 }
        }

        Boy {
            name: "Jack Smith"
            shoe { size: 8; color: "blue"; brand: "Puma"; price: 19.95 }
        }

        Girl {
            name: "Anne Brown"
            BirthdayParty.rsvp: "2009-07-01"
            shoe.size: 7
            shoe.color: "red"
            shoe.brand: "Marc Jacobs"
            shoe.price: 699.99
        }
    }
}
'''


class ShoeDescription(QObject):
    def __init__(self, parent=None):
        super(ShoeDescription, self).__init__(parent)

        self._size = 0
        self._color = QColor()
        self._brand = ''
        self._price = 0.0

    shoeChanged = pyqtSignal()

    @pyqtProperty(int, notify=shoeChanged)
    def size(self):
        return self._size

    @size.setter
    def size(self, size):
        if self._size != size:
            self._size = size
            self.shoeChanged.emit()

    @pyqtProperty(QColor, notify=shoeChanged)
    def color(self):
        return self._color

    @color.setter
    def color(self, color):
        if self._color != color:
            self._color = color
            self.shoeChanged.emit()

    @pyqtProperty(str, notify=shoeChanged)
    def brand(self):
        return self._brand

    @brand.setter
    def brand(self, brand):
        if self._brand != brand:
            self._brand = brand
            self.shoeChanged.emit()

    @pyqtProperty(float, notify=shoeChanged)
    def price(self):
        return self._price

    @price.setter
    def price(self, price):
        if self._price != price:
            self._price = price
            self.shoeChanged.emit()


class Person(QObject):
    def __init__(self, parent=None):
        super(Person, self).__init__(parent)

        self._name = ''
        self._shoe = ShoeDescription()

    nameChanged = pyqtSignal()

    @pyqtProperty(str, notify=nameChanged)
    def name(self):
        return self._name

    @name.setter
    def name(self, name):
        if self._name != name:
            self._name = name
            self.nameChanged.emit()

    @pyqtProperty(ShoeDescription)
    def shoe(self):
        return self._shoe


class Boy(Person):
    pass


class Girl(Person):
    pass


class BirthdayPartyAttached(QObject):
    def __init__(self, parent):
        super(BirthdayPartyAttached, self).__init__(parent)

        self._rsvp = QDate()

    rsvpChanged = pyqtSignal()

    @pyqtProperty(QDate, notify=rsvpChanged)
    def rsvp(self):
        return self._rsvp

    @rsvp.setter
    def rsvp(self, rsvp):
        if self._rsvp != rsvp:
            self._rsvp = rsvp
            self.rsvpChanged.emit()


class BirthdayParty(QObject):
    Q_CLASSINFO('DefaultProperty', 'guests')

    partyStarted = pyqtSignal(QTime, arguments=['time'])

    def __init__(self, parent=None):
        super(BirthdayParty, self).__init__(parent)

        self._host = None
        self._guests = []

    hostChanged = pyqtSignal()

    @pyqtProperty(Person, notify=hostChanged)
    def host(self):
        return self._host

    @host.setter
    def host(self, host):
        if self._host != host:
            self._host = host
            self.hostChanged.emit()

    @pyqtProperty(QQmlListProperty)
    def guests(self):
        return QQmlListProperty(Person, self, self._guests)
    @pyqtSlot(result=int)
    def guestCount(self):
        return len(self._guests)

    def guest(self, idx):
        return self._guests[idx]

    @pyqtProperty(str)
    def announcement(self):
        return ''

    @announcement.setter
    def announcement(self, announcement):
        print(announcement)
    @pyqtSlot()
    def startParty(self):
        self.partyStarted.emit(QTime.currentTime())


class HappyBirthdaySong(QObject, QQmlPropertyValueSource):
    def __init__(self, parent=None):
        super(HappyBirthdaySong, self).__init__(parent)

        self._line = -1
        self._lyrics = []
        self._target = QQmlProperty()
        self._name = ''

        self.timer = QTimer(self)
        self.timer.timeout.connect(self.advance)
        # timer.start(1000)
    @pyqtSlot()
    def start(self):
        self.timer.start(1000)
    nameChanged = pyqtSignal()

    @pyqtProperty(str, notify=nameChanged)
    def name(self):
        return self._name

    @name.setter
    def name(self, name):
        if self._name != name:
            self._name = name

            self._lyrics = [
                "",
                "Happy birthday to you,",
                "Happy birthday to you,",
                "Happy birthday dear %s," % self._name,
                "Happy birthday to you!"
            ]

            self.nameChanged.emit()

    def setTarget(self, target):
        self._target = target

    @pyqtSlot()
    def advance(self):
        self._line += 1

        if self._line < len(self._lyrics):
            self._target.write(self._lyrics[self._line])
        else:
            pass
            # QCoreApplication.instance().quit()


app = QApplication(sys.argv)

qmlRegisterType(BirthdayPartyAttached)
qmlRegisterType(BirthdayParty, "People", 1, 0, "BirthdayParty",
        attachedProperties=BirthdayPartyAttached)
qmlRegisterType(HappyBirthdaySong, "People", 1, 0, "HappyBirthdaySong")
qmlRegisterType(ShoeDescription)
qmlRegisterType(Person)
qmlRegisterType(Boy, "People", 1, 0, "Boy")
qmlRegisterType(Girl, "People", 1, 0, "Girl")

# engine = QQmlEngine()
engine=QQmlApplicationEngine()
print(dir(engine))
engine.loadData(QML)
# component = QQmlComponent(engine)
# component.setData(QML, QUrl())

# party = component.create()

# if party is not None and party.host is not None:
#     print("\"%s\" is having a birthday!" % party.host.name)

#     if isinstance(party.host, Boy):
#         print("He is inviting:")
#     else:
#         print("She is inviting:")

#     for ii in range(party.guestCount()):
#         guest = party.guest(ii)

#         attached = qmlAttachedPropertiesObject(BirthdayParty, guest, False)

#         if attached is not None:
#             rsvpDate = attached.property('rsvp')
#         else:
#             rsvpDate = QDate()

#         if rsvpDate.isNull():
#             print("    \"%s\" RSVP date: Hasn't RSVP'd" % guest.name)
#         else:
#             print("    \"%s\" RSVP date: %s" % (guest.name, rsvpDate.toString()))

#     party.startParty()
# else:
#     for e in component.errors():
#         print("Error:", e.toString());

sys.exit(app.exec_())
